#pragma once
#include <iostream>
#include <queue>
#include <functional>
#include "Thread.hpp"
#include "ThreadPool.hpp"
#include "log.hpp"
#include "LockGuard.hpp"
#include <unistd.h>

static const int defaultnum = 5;

namespace ThreadNs
{

    class ThreadData
    {
    };

    template <typename T>
    class ThreadPool
    {
    private:
        ThreadPool(const ThreadPool<T> &th) = delete;
        const ThreadPool<T> operator=(const ThreadPool<T> &th) = delete;

        ThreadPool(int thread_num = defaultnum)
            : _thread_nums(thread_num)
        {
            // 初始化锁和条件变量
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_cond, nullptr);

            // 先构建若干线程
            for (int i = 0; i < _thread_nums; i++)
            {
                // 创建线程并放入 容器中
                std::string threadname = "Thread-" + std::to_string(i + 1);

                T td;
                Thread<T> t(std::bind(&ThreadPool::ThreadRun, this, std::placeholders::_1), threadname, td);
                // Thread 的构造函数第一个参数为 指定调用函数，后面是函数名

                _threads.push_back(t);
            }
        }
        ~ThreadPool()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }

    public:
        void ThreadWait()
        {
            pthread_cond_wait(&_cond, &_mutex);
        }

        void ThreadWakeup()
        {
            pthread_cond_signal(&_cond);
        }

        // 线程需要处理的任务
        void ThreadRun(T &data) // 这个参数暂时没有用到
        {
            while (true)
            {
                T t;
                {
                    LockGuard LockGuard(&_mutex);
                    //   pthread_mutex_lock(&_mutex);
                    // std::cout << "Thread is running ..." << endl;

                    while (_q.empty())
                    { // 如果任务队列为空，那么在条件上进行等待
                        // pthread_cond_wait(_cond, &mutex);

                        ThreadWait();
                    }
                    t = _q.front(); // 拿任务
                    _q.pop();

                    // pthread_mutex_unlock(&_mutex);
                }

                // 运行任务
                t();

                // cout << "result: " << t.PrintResult() << endl;
            }
        }

        bool Start()
        {
            // 启动
            for (auto &thread : _threads)
            {
                thread.Start();
            }
            return 1;
        }

        void Push(const T &in)
        {
            {
                LockGuard lockguard(&_mutex);
                _q.push(in);
                ThreadWakeup();
            }
        }

        void Wait()
        {
            for (auto &thread : _threads)
            {
                thread.Join();
            }
        }

        static ThreadPool<T> *GetInstance() // 饿汉模式
        {
            if (_instance == nullptr)
            {
                LockGuard lockguard(&sig_lock);

                if (_instance == nullptr)
                {
                    lg.LogMessage(Info, "创建单例成功!");
                    _instance = new ThreadPool<T>();
                }
            }
            return _instance;
        }

    private:
        std::queue<T> _q;
        std::vector<Thread<T>> _threads; // 放线程
        int _thread_nums;
        pthread_mutex_t _mutex;
        pthread_cond_t _cond;

        static ThreadPool<T> *_instance; //= nullptr; // 单例指针
        // 类内初始化静态成员时需要constexpr,但是该变量必须是常量,或者用const修饰

        static pthread_mutex_t sig_lock; //= PTHREAD_MUTEX_INITIALIZER;
        // 在多线程下获取 GetInstance()  是有风险的，所以需要一把全局的锁将GetInstance 进行封锁
        // 这个初始化也可以在类外进行，此时就无需 constexpr

        // load   定义负载负载，如果线程不够，可以动态增加，线程等待过多，可以释放掉一些资源
        // int numeber{1};

        // int _thread_num_low_water;  // 进程数量低水位线
        // int _thread_num_high_water; // 进程数量高水位线

        // int _task_num_low_water; // 任务数量低水位线
        // int _task_num_high_wate; // 任务数量低水位线
    };

    // 也可以在类外进行初始化
    template <typename T>
    ThreadPool<T> *ThreadPool<T>::_instance = nullptr;

    template <typename T>
    pthread_mutex_t ThreadPool<T>::sig_lock = PTHREAD_MUTEX_INITIALIZER;

}
